Skip to content

feat(web): React UI v2.0 — Phase 2 Tasks 26+27+30+31 (data hooks + selectedRef)#22

Merged
aksOps merged 4 commits into
mainfrom
feat/web-phase-2-batch-c
May 16, 2026
Merged

feat(web): React UI v2.0 — Phase 2 Tasks 26+27+30+31 (data hooks + selectedRef)#22
aksOps merged 4 commits into
mainfrom
feat/web-phase-2-batch-c

Conversation

@aksOps

@aksOps aksOps commented May 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 2 Batch C subset of React UI v2.0 — the data composition layer that turns the primitives from Batch A/B into hooks that components can consume directly. After this lands, only Tasks 28 (useApprovalsQueue) and 29 (useAgentDefinitions) remain in Phase 2; both are independent and dispatch in parallel as a final mini-batch.

  • Task 26useSessionFull(sid) (web/src/state/useSessionFull.ts) — composes useReducer(sessionReducer) + apiFetch('/sessions/{sid}/full') for bootstrap + useEventSource('/sessions/{sid}/events') for live deltas. Exposes { state, isLoading, error, refresh }. SSE gated on bootstrapped flag so no event lands before initial state. 3 tests.
  • Task 27useSessionList() (web/src/state/useSessionList.ts) — fetch /sessions + subscribe /sessions/recent/events for session.created/session.status_changed/session.agent_running deltas. SessionSummary shape kept local to the hook (not promoted to types.ts until Phase 3 needs it). 3 tests.
  • Task 30useUiHints() (web/src/state/useUiHints.ts) — @tanstack/react-query cache-once for /config/ui-hints. staleTime: Infinity, gcTime: Infinity since UiConfig is loaded at app startup and immutable. 2 tests.
  • Task 31selectedRef (web/src/state/selectedRef.tsx) — React Context selection model with { kind: 'agent'|'tool_call'|'message'|null, id?: string }. Two-context split (value + setter) so components that only call useSetSelected() don't re-render on selection change. Throws when consumed outside Provider. 4 tests.

Validation

  • cd web && npm install → 0 vulnerabilities
  • npm run typecheck → exit 0
  • npx vitest run58 passed / 0 failed (Phase 2 Batch B's 46 + 12 new)
  • npm run build → clean

Nothing touches src/runtime/ — no dist/app.py regen.

Design notes

  • Hooks compose existing primitives (apiFetch, useEventSource, sessionReducer) — no logic duplication.
  • useSessionList uses setState rather than the reducer because cross-session deltas don't need vm_seq watermarking (each session has its own seq scope).
  • selectedRef deliberately uses Context rather than Zustand to avoid the dep. The two-context split (SelectedRefContext + SetSelectedRefContext) keeps re-renders narrow when only the setter is consumed.
  • useUiHints doesn't share the _helpers/render.tsx test wrapper — it inlines its own QueryClient with gcTime: 0 for test isolation. Intentional.

Out of scope (next batch)

  • Task 28 useApprovalsQueue() — derived from useSessionList(), filters pending-approval tool calls.
  • Task 29 useAgentDefinitions() — react-query cache-once for /api/v1/agents.

Both will land in a final Phase 2 Batch D (parallel, ~10 min total) before Phase 3 (Shell components) starts.

Test plan

  • Vitest: 58/58 pass
  • Typecheck: exit 0
  • Build: clean
  • Pytest backend stays green (no backend changes)
  • CI: lint + type + test + sonar + bundle + skill-lint
  • CI: SonarCloud quality gate

🤖 Generated with Claude Code

@sonarqubecloud

Copy link
Copy Markdown

@aksOps aksOps merged commit aa0fa90 into main May 16, 2026
9 checks passed
@aksOps aksOps deleted the feat/web-phase-2-batch-c branch May 16, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant